package com.media.entrance.service;

import com.media.entrance.model.AgentStatusEnum;
import com.media.entrance.model.MatchAndResourceModel;
import com.media.entrance.model.MatchInfo;
import com.media.entrance.config.MediaRouterOptions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
@Slf4j
public class MatchService {

    private final String ZSET_TAG = "waitingLine";
    @Autowired
    private RedisService redisService;

    @Autowired
    private MediaRouterOptions mediaRouterOptions;
    @Autowired
    private OperateDatabaseService operateDatabaseService;

    // 匹配逻辑，如果坐席振铃取消了，那么重新排队
    // 2.0接口，3.0已废弃
    @Deprecated
    public AgentStatusEnum requestMatchAgent(MatchAndResourceModel matchInfo) {
        // 查询是否已经匹配且接听
        MatchInfo temp = operateDatabaseService.findByDeviceId(matchInfo.getDeviceId());
        if (temp != null) {
            matchInfo.setDeviceId(temp.getDeviceId());
            matchInfo.setRoomId(temp.getRoomId());
            matchInfo.setAgentId(temp.getAgentId());
            if (temp.getAgentStatus().equals("busy")) {
                return AgentStatusEnum.BUSY;
            } else {
                return AgentStatusEnum.RING;
            }
        }
        // 进行匹配
        temp = operateDatabaseService.findByAgentStatus("idle");
        if (temp == null) { //如果没有空闲坐席，进入排队，返回排队数
            long rank = redisService.rankZset(ZSET_TAG, matchInfo.getDeviceId());
            if (rank < 0) {
                long totalNum = redisService.countZset(ZSET_TAG);
                // 排队上线逻辑
                if (totalNum >= mediaRouterOptions.getMaxWaitingLineLimit()) {
                    return AgentStatusEnum.OTHER;
                } else {
                    redisService.addZset(ZSET_TAG, matchInfo.getDeviceId(), (new Date()).getTime());
                    matchInfo.setQueueNo(totalNum);
                    matchInfo.setQueueLimit(mediaRouterOptions.getMaxWaitingLineLimit());
                }
            } else {
                matchInfo.setQueueNo(rank);
            }
            return AgentStatusEnum.IDLE;
        } else { //如果有空闲坐席，则进入排队
            // 如果当前有排队数
            if (redisService.countZset(ZSET_TAG) > 1) {
                // 取出第一个排队的设备，进行匹配
                long rank = redisService.rankZset(ZSET_TAG, matchInfo.getDeviceId());
                if (rank != 0) {
                    matchInfo.setQueueNo(rank);
                    return AgentStatusEnum.IDLE;
                }else {
                    redisService.removeZset(ZSET_TAG, matchInfo.getDeviceId());
                }
            }
            temp.setDeviceId(matchInfo.getDeviceId());
            temp.setAgentStatus("ring");
            //生成uuid
            long time = System.currentTimeMillis();
            int random = (int) (Math.random() * Integer.MAX_VALUE);
            UUID uuid = new UUID(time, random);
            temp.setRoomId(uuid.toString());
            int result = operateDatabaseService.updateMatchInfo(temp);
            if (result > 0) {
                matchInfo.setDeviceId(temp.getDeviceId());
                matchInfo.setRoomId(uuid.toString());
                matchInfo.setAgentId(temp.getAgentId());
                matchInfo.setQueueNo(null);
                return AgentStatusEnum.RING;
            } else {
                return AgentStatusEnum.OTHER;
            }
        }
    }

    // 这个方面支持历史状态变更信息，解决了呼叫未匹配的问题
    // 2.0接口，3.0已废弃
    @Deprecated
    public AgentStatusEnum requestMatchAgent(MatchAndResourceModel matchInfo, AgentStatusEnum lastStatus) {

        // 查询是否已经匹配且接听
        MatchInfo temp = operateDatabaseService.findByDeviceId(matchInfo.getDeviceId());
        if (temp != null) {
            log.info(matchInfo.getDeviceId() + "already not idle + " + matchInfo);
            matchInfo.setDeviceId(temp.getDeviceId());
            matchInfo.setRoomId(temp.getRoomId());
            matchInfo.setAgentId(temp.getAgentId());
            if (temp.getAgentStatus().equals("busy")) {
                return AgentStatusEnum.BUSY;
            } else {
                return AgentStatusEnum.RING;
            }
        }
        // 修改两个坐席同时取消时，排队第一个优先被匹配
        if (lastStatus.equals(AgentStatusEnum.RING)) {
            // 放到最前面，同时score为0，则按字母排序
            redisService.addZset(ZSET_TAG, matchInfo.getDeviceId(), 0);
        }
        // 处理振铃不通时的特殊处理
        temp = operateDatabaseService.findByAgentStatus("idle");

        // 进行匹配
        if (temp == null) { //如果没有空闲坐席，进入排队，返回排队数
            // 如果上次状态是振铃，本次不是振铃的化，说明坐席取消了一次
            long rank = redisService.rankZset(ZSET_TAG, matchInfo.getDeviceId());
            log.info(matchInfo.getDeviceId() + "has no idle agent, current rank:" + rank);
            if (rank < 0) {
//                if (lastStatus.equals(AgentStatusEnum.RING)) {
//                    // 放到最前面
//                    redisService.addZset(ZSET_TAG, matchInfo.getDeviceId(), 0);
//                    matchInfo.setQueueNo(redisService.rankZset(ZSET_TAG, matchInfo.getDeviceId()));
//                } else {
                    long totalNum = redisService.countZset(ZSET_TAG);
                    long limitNum = mediaRouterOptions.getMaxWaitingLineLimit();
                    // 达到排队上线的处理
                    if (totalNum >= limitNum) {
                        log.info("current:" + totalNum + "limit num: " + limitNum);
                        return AgentStatusEnum.OTHER;
                    } else {
                        redisService.addZset(ZSET_TAG, matchInfo.getDeviceId(), (new Date()).getTime());
                        matchInfo.setQueueNo(totalNum);
                        matchInfo.setQueueLimit(limitNum);
                    }
//                }
            } else {
                matchInfo.setQueueNo(rank);
            }
            return AgentStatusEnum.IDLE;
        } else { //如果有空闲坐席，则进入排队
            // 如果当前有排队数
            long count = redisService.countZset(ZSET_TAG);
            log.info(matchInfo.getDeviceId() + "has idle agent, current queue count:" + count);
            if ( count >= 1) {
                // 取出第一个排队的设备，进行匹配
                long rank = redisService.rankZset(ZSET_TAG, matchInfo.getDeviceId());
                log.info(matchInfo.getDeviceId() + "has idle agent, current queue count:" + count + " current rank:"  + rank);
                if (rank > 0) {
                    matchInfo.setQueueNo(rank);
                    return AgentStatusEnum.IDLE;
                } else if (rank < 0) { // 队列中没有自己
                    // 继续匹配即可
                    log.info(matchInfo.getDeviceId() + "is not in queue");
                }else {
                    redisService.removeZset(ZSET_TAG, matchInfo.getDeviceId());
                }
            }
            temp.setDeviceId(matchInfo.getDeviceId());
            temp.setAgentStatus("ring");
            //生成uuid
            long time = System.currentTimeMillis();
            int random = (int) (Math.random() * Integer.MAX_VALUE);
            UUID uuid = new UUID(time, random);
            temp.setRoomId(uuid.toString());
            int result = operateDatabaseService.updateMatchInfo(temp);
            if (result > 0) {
                matchInfo.setDeviceId(temp.getDeviceId());
                matchInfo.setRoomId(uuid.toString());
                matchInfo.setAgentId(temp.getAgentId());
                matchInfo.setQueueNo(null);
                return AgentStatusEnum.RING;
            } else {
                log.error("update db fail! " + temp);
                return AgentStatusEnum.OTHER;
            }
        }
    }

    // 取消匹配，考虑3种情况
    public Set<String> cancelMatch(String deviceId) {
         // 查询是否已经匹配且接听
        MatchInfo temp = operateDatabaseService.findByDeviceId(deviceId);
        if (temp != null) {
            if (temp.getAgentStatus().equals("busy")) {
                log.info("MatchService: cancelMatch: find deviceId:[" + deviceId + "],agentId:[" + temp.getAgentId() +"] is busy, do nothing");
            } else {
                log.info("MatchService: cancelMatch: find deviceId:[" + deviceId + "],agentId:[" + temp.getAgentId() +"] is ring, update to idle");
                if (!updateAgentRingOrBusyToIdle(temp.getAgentId())) {
                    log.error("MatchService: cancelMatch: find deviceId:[" + deviceId + "],agentId:[" + temp.getAgentId() +"] is ring, update fail!");
                }
            }
            return null;
        } else {
            log.info("MatchService: cancelMatch: find deviceId:[" + deviceId + "] is idle, clean redis!");
            return clearQueue(deviceId);
        }
    }

    public Set<String> clearQueue(String deviceId) {
        long rank = redisService.rankZset(ZSET_TAG, deviceId);
        if ( rank >= 0) {
            long result = redisService.removeZset(ZSET_TAG, deviceId);
            if (result != 1){
                log.error("MatchService: clearQueue: find deviceId:[" + deviceId + "] is idle, clean redis zset fail!");
                return null;
            }
            return redisService.rangeZset(ZSET_TAG, rank, -1);
        } else {
            log.warn("MatchService: clearQueue: find deviceId:[" + deviceId + "] is idle, not in redis zset!");
            return null;
        }
    }

    // 重新设置socre为0，进匹配，返回当前排名（排名可能不为0）
    public long rePutInQueue(String deviceId) {
        // 放到最前面，同时score为0，则按字母排序
        if (redisService.addZset(ZSET_TAG, deviceId, 0)){
            return redisService.rankZset(ZSET_TAG, deviceId);
        } else {
            log.error("MatchService: reMatch: add to redis zset fail");
            return -1;
        }
    }

    //获取当前的位置
    public long getPostionInQueue(String deviceId){
        return redisService.rankZset(ZSET_TAG, deviceId);
    }
    //遍历所有队列内容
    public Set<String> findAllDeviceInQueue() {
        return redisService.rangeZset(ZSET_TAG, 0, -1);
    }

    //删除所有队列内容
    public long removeRangeQueue(long start, long end){
        return redisService.removeZSetRange(ZSET_TAG, start, end);
    }

    // 暴露一些数据库的查询接口
    public MatchInfo getInitAgentByAgentId(String agentId) {
        return operateDatabaseService.findByInitAgentId(agentId);
    }

    public MatchInfo getAgentByRoomId(String roomId) {
        return operateDatabaseService.findByRoomId(roomId);
    }

    public MatchInfo getAgentByAgentId(String agentId) {
        return operateDatabaseService.findByAgentId(agentId);
    }

    public List<MatchInfo> getAllAgentsByStatus(String agentStatus) {
        return operateDatabaseService.findAllByAgentStatus(agentStatus);
    }

    public int registerOneAgent(String agentId) {
        MatchInfo matchInfo = new MatchInfo(agentId, "idle", null, null);
        return operateDatabaseService.insertMatchInfo(matchInfo);
    }

    // 计入流水库
    public void recordAgentChangeRecords(MatchAndResourceModel matchInfo) {
        // 计入流水库
        int result = operateDatabaseService.insertMatchAndResourceModelToAgentRecorder(matchInfo);
        if (result == 1) {
            log.info("MatchService: recordAgentChangeRecords: recorder success!");
        } else {
            log.error("MatchService: recordAgentChangeRecords: recorder:[" + matchInfo + "] failed!");
        }
    }

    public void recordDeviceChangeRecords(MatchAndResourceModel matchInfo) {
        // 计入流水库
        int result = operateDatabaseService.insertMatchAndResourceModelToDeviceRecorder(matchInfo);
        if (result == 1) {
            log.info("MatchService: recordDeviceChangeRecords: recorder success!");
        } else {
            log.error("MatchService: recordDeviceChangeRecords: recorder:[" + matchInfo + "] failed!");
        }
    }


    // 查询客户的上次连接的结果
    public MatchAndResourceModel getDeviceIdLastMatchResult(String deviceId){
        MatchInfo temp = operateDatabaseService.findByDeviceId(deviceId);
        if (temp != null) {
            MatchAndResourceModel result = new MatchAndResourceModel();
            result.setAgentId(temp.getAgentId());
            result.setRoomId(temp.getRoomId());
            result.setDeviceId(temp.getDeviceId());
            result.setReason(temp.getAgentStatus());
            return result;
        }
        return null;
    }

    // 设备匹配坐席
    // 3.0接口
    public MatchAndResourceModel requestMatchAgentNew(String deviceId) {
        // 查询空闲状态（带悲观锁）
        MatchInfo temp = operateDatabaseService.findByAgentStatus("idle");
        MatchAndResourceModel matchInfo = new MatchAndResourceModel();
        matchInfo.setDeviceId(deviceId);
        long limitNum = mediaRouterOptions.getMaxWaitingLineLimit();
        // 进行匹配
        if (temp == null) { //如果没有空闲坐席，进入排队，返回排队数
            // 如果上次状态是振铃，本次不是振铃的化，说明坐席取消了一次
            long rank = redisService.rankZset(ZSET_TAG, deviceId);
            log.info("MatchService：requestMatchAgentNew: deviceId:" + deviceId + "has no idle agent, current rank:" + rank);
            if (rank < 0) {
                // 说明没再队列里，需要增加队列
                long totalNum = redisService.countZset(ZSET_TAG);

                // 如果排队总数达到排队上线的处理
                if (totalNum >= limitNum) {
                    log.info("MatchService：requestMatchAgentNew: current:" + totalNum + "limit num: " + limitNum);
                    matchInfo.setReason("domatch over max queue limit");
                    return matchInfo;
                } else {
                    redisService.addZset(ZSET_TAG, deviceId, (new Date()).getTime());
                    matchInfo.setQueueNo(totalNum);
                    matchInfo.setQueueLimit(limitNum);
                }
            } else {
                // 理论上走不到这里
                log.warn("MatchService：requestMatchAgentNew: not first requestMatchAgent");
                matchInfo.setQueueNo(rank);
            }
            return matchInfo;
        } else { //如果有空闲坐席，则进入排队
            // 如果当前有排队数
            long count = redisService.countZset(ZSET_TAG);
            log.info(deviceId + " has idle agent, current queue count:" + count);
            if ( count >= 1) {
                // 取出第一个排队的设备，进行匹配，理论上不会走到
                long rank = redisService.rankZset(ZSET_TAG, deviceId);
                log.warn("requestMatchAgentNew: deviceId:" + matchInfo.getDeviceId() + "has idle agent, current queue count:" + count + " current rank:"  + rank);
                if (rank > 0) {
                    matchInfo.setQueueNo(rank);
                    matchInfo.setQueueLimit(limitNum);
                    return matchInfo;
                } else if (rank < 0) { // 队列中没有自己
                    // 继续匹配即可
                    log.info(matchInfo.getDeviceId() + "is not in queue");
                }else {
                    redisService.removeZset(ZSET_TAG, deviceId);
                }
            }
            return oneDeviceMatchOneAgent(deviceId, temp.getAgentId());
        }
    }

    public MatchAndResourceModel oneDeviceMatchOneAgent(String deviceId, String agentId) {
        MatchAndResourceModel matchAndResourceModel = new MatchAndResourceModel();
        if (agentId == null){
            log.warn("MatchService：oneDeviceMatchOneAgent: agentId is null");
            matchAndResourceModel.setDeviceId(deviceId);
            matchAndResourceModel.setQueueNo(redisService.rankZset(ZSET_TAG, deviceId));
            matchAndResourceModel.setQueueLimit(mediaRouterOptions.getMaxWaitingLineLimit());
            return matchAndResourceModel;
        } else if (deviceId == null) {
            log.error("MatchService：oneDeviceMatchOneAgent: deviceId is null, impossible to here");
            matchAndResourceModel.setReason("there is no device");
            matchAndResourceModel.setAgentId(agentId);
            return matchAndResourceModel;
        }
        //生成uuid
        long time = System.currentTimeMillis();
        int random = (int) (Math.random() * Integer.MAX_VALUE);
        UUID uuid = new UUID(time, random);
        if (updateAgentIdleToRing(agentId, deviceId, uuid.toString())) {
            matchAndResourceModel.setDeviceId(deviceId);
            matchAndResourceModel.setRoomId(uuid.toString());
            matchAndResourceModel.setAgentId(agentId);
            matchAndResourceModel.setQueueNo(null);
            return matchAndResourceModel;
        } else {
            log.error("MatchService：oneDeviceMatchOneAgent: update db fail! ");
            matchAndResourceModel.setDeviceId(deviceId);
            matchAndResourceModel.setQueueNo(rePutInQueue(deviceId));
            matchAndResourceModel.setQueueLimit(mediaRouterOptions.getMaxWaitingLineLimit());
            matchAndResourceModel.setReason("update db fail");
            return matchAndResourceModel;
        }
    }

    // 3.0 新接口，批量匹配函数，单线程的，目前不在使用
    @Deprecated
    public List<MatchAndResourceModel> scheduleDoBatchMatch(Set<String> deviceIds) {
        // 查询所有空闲坐席信息
        List<MatchInfo> matchInfos = operateDatabaseService.findAllByAgentStatus("idle");
        int agentNum = matchInfos.size();
        if (agentNum == 0) {
            log.info("doBatchMatch: no idle agent!");
            return null;
        }
        String[] deviceIdsArray = deviceIds.toArray(new String[0]);
        int deviceNum = deviceIdsArray.length;
        int index = 0;
        List<MatchAndResourceModel> listResult = new ArrayList<>();
        // 构建要返回的信息
        if (deviceNum < agentNum) {
            for (String deviceId:deviceIds){
                String agentId = matchInfos.get(index++).getAgentId();
                listResult.add(oneDeviceMatchOneAgent(deviceId, agentId));
            }
            // 清空队列
            removeRangeQueue(0, -1);
        } else {
            for (MatchInfo matchInfo: matchInfos){
                String agentId = matchInfo.getAgentId();
                String deviceId = deviceIdsArray[index++];
                listResult.add(oneDeviceMatchOneAgent(deviceId, agentId));
            }
            // 清除队列
            long result = removeRangeQueue(0, index - 1);
            if (result != index) {
                log.warn("MatchService: scheduleDoBatchMatch: removed zset number: " + result + " want removed zset number + " + index);
            }
            MatchAndResourceModel match;
            for (int i = index; i < deviceNum; i++){
                match = new MatchAndResourceModel();
                match.setQueueLimit(mediaRouterOptions.getMaxWaitingLineLimit());
                match.setQueueNo(Integer.toUnsignedLong(i - index));
                match.setDeviceId(deviceIdsArray[i]);
                listResult.add(match);
            }
        }
        return listResult;
    }

    // 更新数据库时增加事务和乐观锁
    @Transactional
    public boolean updateAgentInitToIdle(String agentId) {
        MatchInfo oldMatchInfo = operateDatabaseService.findByInitAgentIdWithLock(agentId);
        if (oldMatchInfo.getAgentStatus().equals("init")) {
            MatchInfo matchInfo = new MatchInfo(agentId, "idle", null, null);
            int result = operateDatabaseService.updateMatchInfo(matchInfo, "init");
            if (result == 1) {
                // 只有成功才计入流水库
                recordAgentChangeRecords(matchInfo.changeToMatchAndResourceModel());
                return true;
            }
        } else {
            log.error("MatchService:updateAgentInitToIdle:status:" + oldMatchInfo.getAgentStatus());
        }
        return false;
    }

    // 更新数据库时增加事务和乐观锁
    @Transactional
    public boolean updateAgentIdleToInit(String agentId) {
        MatchInfo oldMatchInfo = operateDatabaseService.findByAgentIdWithLock(agentId);
        if (oldMatchInfo.getAgentStatus().equals("idle")) {
            MatchInfo matchInfo = new MatchInfo(agentId, "init", null, null);
            int result = operateDatabaseService.updateMatchInfo(matchInfo, "idle");
            if (result == 1) {
                // 只有成功才计入流水库
                recordAgentChangeRecords(matchInfo.changeToMatchAndResourceModel());
                return true;
            }
        } else {
            log.error("MatchService:updateAgentIdleToInit:status:" + oldMatchInfo.getAgentStatus());
        }
        return false;
    }

    @Transactional
    public boolean updateAgentIdleToRest(String agentId) {
        MatchInfo oldMatchInfo = operateDatabaseService.findByAgentIdWithLock(agentId);
        if (oldMatchInfo.getAgentStatus().equals("idle")) {
            MatchInfo matchInfo = new MatchInfo(agentId, "rest", null, null);
            int result = operateDatabaseService.updateMatchInfo(matchInfo, "idle");
            if (result == 1) {
                // 只有成功才计入流水库
                recordAgentChangeRecords(matchInfo.changeToMatchAndResourceModel());
                return true;
            }
        } else {
            log.error("MatchService:updateAgentIdleToRest:status:" + oldMatchInfo.getAgentStatus());
        }
        return false;
    }

    @Transactional
    public boolean updateAgentIdleToPause(String agentId) {
        MatchInfo oldMatchInfo = operateDatabaseService.findByAgentIdWithLock(agentId);
        if (oldMatchInfo.getAgentStatus().equals("idle")) {
            MatchInfo matchInfo = new MatchInfo(agentId, "pause", null, null);
            int result = operateDatabaseService.updateMatchInfo(matchInfo, "idle");
            if (result == 1) {
                // 只有成功才计入流水库
                recordAgentChangeRecords(matchInfo.changeToMatchAndResourceModel());
                return true;
            }
        } else {
            log.error("MatchService:updateAgentIdleToPause:status:" + oldMatchInfo.getAgentStatus());
        }
        return false;
    }

    // 更新数据库时增加事务和乐观锁
    @Transactional
    public boolean updateAgentIdleToRing(String targetAgentId, String deviceId, String targetRoomId) {
        MatchInfo oldMatchInfo = operateDatabaseService.findByAgentIdWithLock(targetAgentId);
        if (oldMatchInfo.getAgentStatus().equals("idle")) {
            MatchInfo matchInfo = new MatchInfo(targetAgentId, "ring", deviceId, targetRoomId);
            int result = operateDatabaseService.updateMatchInfo(matchInfo, "idle");
            if (result == 1) {
                // 只有成功才计入流水库
                recordAgentChangeRecords(matchInfo.changeToMatchAndResourceModel());
                return true;
            }
        } else {
            log.error("MatchService:updateAgentIdleToRing:dbstatus:" + oldMatchInfo.getAgentStatus());
        }
        return false;
    }

    // 更新数据库时增加事务和乐观锁
    @Transactional
    public boolean updateAgentRingToBusy(String targetAgentId) {
        MatchInfo matchInfo = operateDatabaseService.findByAgentIdWithLock(targetAgentId);
        if (matchInfo.getAgentStatus().equals("ring")) {
            matchInfo.setAgentStatus("busy");
            int result = operateDatabaseService.updateMatchInfo(matchInfo, "ring");
            if (result == 1) {
                // 只有成功才计入流水库
                recordAgentChangeRecords(matchInfo.changeToMatchAndResourceModel());
                return true;
            }
        } else {
            log.error("MatchService:updateAgentRingToBusy:status:" + matchInfo.getAgentStatus());
        }
        return false;
    }

    // 更新数据库时增加事务和乐观锁
    @Transactional
    public boolean updateAgentRingOrBusyToIdle(String agentId) {
        MatchInfo oldMatchInfo = operateDatabaseService.findByAgentIdWithLock(agentId);
        MatchInfo matchInfo = new MatchInfo(agentId, "idle", null, null);
        int result;
        if (oldMatchInfo.getAgentStatus().equals("ring")) {
            result = operateDatabaseService.updateMatchInfo(matchInfo, "ring");
        } else if (oldMatchInfo.getAgentStatus().equals("busy")) {
            result = operateDatabaseService.updateMatchInfo(matchInfo, "busy");
        } else {
            log.error("MatchService:updateAgentRingOrBusyToIdle:status:" + oldMatchInfo.getAgentStatus());
            return false;
        }
        if (result == 1) {
            // 只有成功才计入流水库
            recordAgentChangeRecords(matchInfo.changeToMatchAndResourceModel());
            return true;
        }
        return false;
    }

    // 更新数据库时增加事务和乐观锁
    @Transactional
    public boolean updateAgentRestToPause(String agentId) {
        MatchInfo oldMatchInfo = operateDatabaseService.findByAgentIdWithLock(agentId);
        if (oldMatchInfo.getAgentStatus().equals("rest")) {
            MatchInfo matchInfo = new MatchInfo(agentId, "pause", null, null);
            int result = operateDatabaseService.updateMatchInfo(matchInfo, "rest");
            if (result == 1) {
                // 只有成功才计入流水库
                recordAgentChangeRecords(matchInfo.changeToMatchAndResourceModel());
                return true;
            }
        } else {
            log.error("MatchService:updateAgentRestToPause:status:" + oldMatchInfo.getAgentStatus());
        }
        return false;
    }

    // 更新数据库时增加事务和乐观锁
    @Transactional
    public boolean updateAgentRestOrPauseToIdle(String agentId) {
        MatchInfo oldMatchInfo = operateDatabaseService.findByAgentIdWithLock(agentId);
        MatchInfo matchInfo = new MatchInfo(agentId, "idle", null, null);
        int result;
        if (oldMatchInfo.getAgentStatus().equals("rest")) {
            result = operateDatabaseService.updateMatchInfo(matchInfo, "rest");
        } else if (oldMatchInfo.getAgentStatus().equals("pause")) {
            result = operateDatabaseService.updateMatchInfo(matchInfo, "pause");
        } else {
            log.error("MatchService:updateAgentRestOrPauseToIdle:status:" + oldMatchInfo.getAgentStatus());
            return false;
        }
        if (result == 1) {
            // 只有成功才计入流水库
            recordAgentChangeRecords(matchInfo.changeToMatchAndResourceModel());
            return true;
        }
        return false;
    }

    // 更新数据库时增加redis分布式悲观锁
    public boolean updateAgentInitToIdleWithRedisLock(String agentId) {
        if (redisService.lock(agentId)) {
            MatchInfo oldMatchInfo = operateDatabaseService.findByInitAgentIdWithLock(agentId);
            if (oldMatchInfo.getAgentStatus().equals("init")) {
                MatchInfo matchInfo = new MatchInfo(agentId, "idle", null, null);
                int result = operateDatabaseService.updateMatchInfo(matchInfo);
                if (result == 1) {
                    // 计入流水库
                    recordAgentChangeRecords(matchInfo.changeToMatchAndResourceModel());
                    redisService.unlock(agentId);
                    return true;
                }
            } else {
                log.error("MatchService:updateAgentInitToIdle:status:" + oldMatchInfo.getAgentStatus());
            }
            redisService.unlock(agentId);
        } else {
            log.error("MatchService:updateAgentInitToIdleWithRedisLock: lock fail!");
        }

        return false;
    }

    public boolean updateAgentIdleToInitWithRedisLock(String agentId) {
        if (redisService.lock(agentId)) {
            MatchInfo oldMatchInfo = operateDatabaseService.findByAgentIdWithLock(agentId);
            if (oldMatchInfo.getAgentStatus().equals("idle")) {
                MatchInfo matchInfo = new MatchInfo(agentId, "init", null, null);
                int result = operateDatabaseService.updateMatchInfo(matchInfo);
                if (result == 1) {
                    // 计入流水库
                    recordAgentChangeRecords(matchInfo.changeToMatchAndResourceModel());
                    redisService.unlock(agentId);
                    return true;
                }
            } else {
                log.error("MatchService:updateAgentIdleToInit:status:" + oldMatchInfo.getAgentStatus());
                redisService.unlock(agentId);
            }
        } else {
            log.error("MatchService:updateAgentInitToIdleWithRedisLock: lock fail!");
        }
        return false;
    }

    public boolean updateAgentIdleToRingWithRedisLock(String targetAgentId, String deviceId, String targetRoomId) {
        if (redisService.lock(targetAgentId)) {
            MatchInfo oldMatchInfo = operateDatabaseService.findByAgentIdWithLock(targetAgentId);
            if (oldMatchInfo.getAgentStatus().equals("idle")) {
                MatchInfo matchInfo = new MatchInfo(targetAgentId, "ring", deviceId, targetRoomId);
                int result = operateDatabaseService.updateMatchInfo(matchInfo);
                if (result == 1) {
                    // 计入流水库
                    recordAgentChangeRecords(matchInfo.changeToMatchAndResourceModel());
                    redisService.unlock(targetAgentId);
                    return true;
                }
            } else {
                log.error("MatchService:updateAgentIdleToRing:status:" + oldMatchInfo.getAgentStatus());
            }
            redisService.unlock(targetAgentId);
        } else {
            log.error("MatchService:updateAgentInitToIdleWithRedisLock: lock fail!");
        }
        return false;
    }

    public boolean updateAgentRingToBusyWithRedisLock(String targetAgentId) {
        if (redisService.lock(targetAgentId)) {
            MatchInfo matchInfo = operateDatabaseService.findByAgentIdWithLock(targetAgentId);
            if (matchInfo.getAgentStatus().equals("ring")) {
                matchInfo.setAgentStatus("busy");
                int result = operateDatabaseService.updateMatchInfo(matchInfo);
                if (result == 1) {
                    // 计入流水库
                    recordAgentChangeRecords(matchInfo.changeToMatchAndResourceModel());
                    redisService.unlock(targetAgentId);
                    return true;
                }
            } else {
                log.error("MatchService:updateAgentRingToBusy:status:" + matchInfo.getAgentStatus());
            }
            redisService.unlock(targetAgentId);
        } else {
            log.error("MatchService:updateAgentInitToIdleWithRedisLock: lock fail!");
        }
        return false;
    }

    public boolean updateAgentRingOrBusyToIdleWithRedisLock(String agentId) {
        if (redisService.lock(agentId)) {
            MatchInfo oldMatchInfo = operateDatabaseService.findByAgentId(agentId);
            if (oldMatchInfo.getAgentStatus().equals("ring") || oldMatchInfo.getAgentStatus().equals("busy")) {
                MatchInfo matchInfo = new MatchInfo(agentId, "idle", null, null);
                int result = operateDatabaseService.updateMatchInfo(matchInfo);
                if (result == 1) {
                    // 计入流水库
                    recordAgentChangeRecords(matchInfo.changeToMatchAndResourceModel());
                    redisService.unlock(agentId);
                    return true;
                }
            } else {
                log.error("MatchService:updateAgentRingOrBusyToIdle:status:" + oldMatchInfo.getAgentStatus());
            }
            redisService.unlock(agentId);
        } else {
            log.error("MatchService:updateAgentInitToIdleWithRedisLock: lock fail!");
        }
        return false;
    }
}
